package cn.edu.neusoft.demo.hospital2.Service.impl;

import cn.edu.neusoft.demo.hospital2.Dao.*;
import cn.edu.neusoft.demo.hospital2.common.BusinessException;
import cn.edu.neusoft.demo.hospital2.common.ResourceNotFoundException;
import cn.edu.neusoft.demo.hospital2.pojo.*;
import cn.edu.neusoft.demo.hospital2.Service.AppointmentService;
import cn.edu.neusoft.demo.hospital2.pojo.dto.DepartmentStatsDTO;
import cn.edu.neusoft.demo.hospital2.pojo.dto.RegistrationDTO;
import cn.edu.neusoft.demo.hospital2.pojo.dto.RegistrationDetailDTO;
import cn.edu.neusoft.demo.hospital2.pojo.dto.RegistrationQuery;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Pageable;
import java.util.List;

@Service
public class AppointmentServiceImpl implements AppointmentService {
    private static final Logger logger = LoggerFactory.getLogger(AppointmentServiceImpl.class);

    @Autowired
    private PatientDoctorDao patientDoctorDao;
    @Autowired
    private DoctorWorkDao doctorWorkDao;
    @Autowired
    private DepartmentDao departmentDao;
    @Autowired
    private MessageboardDao messageboardDao;
    @Autowired
    private MedicalRecordDao medicalRecordDao;

    @Override
    public List<DoctorWork> getDoctorWorkList(DoctorWork doctorWork) {
        logger.info("查询医生可预约列表：doctorId={}, day={}",
                doctorWork.getDocId(), doctorWork.getDay());
        return doctorWorkDao.getDoctorWorkList(doctorWork);
    }

    @Override
    @Transactional
    public boolean makeAppointment(PatientDoctor patientDoctor) {
        try {
            // 1. 检查预约是否已存在
            List<PatientDoctor> existingAppointments =
                    patientDoctorDao.getAppointmentsByPatientId(patientDoctor.getPatientId());

            for (PatientDoctor appointment : existingAppointments) {
                if (appointment.getDocId().equals(patientDoctor.getDocId()) &&
                        appointment.getDay().equals(patientDoctor.getDay()) &&
                        appointment.getTimePeriod().equals(patientDoctor.getTimePeriod())) {
                    
                    // 修改这里，只允许状态为2（已取消）的预约再次预约
                    if (!"2".equals(appointment.getStatus())) { // 使用getStatus()方法获取预约状态
                        logger.error("预约失败：患者 {} 已在 {} {} 预约医生 {}",
                                patientDoctor.getPatientId(),
                                patientDoctor.getDay(),
                                patientDoctor.getTimePeriod(),
                                patientDoctor.getDocId());
                        return false;
                    }
                }
            }

            // 2. 检查医生是否有可预约号源
            DoctorWork doctorWork = doctorWorkDao.getDoctorWorkByDayAndDocId(
                    patientDoctor.getDay(),
                    patientDoctor.getDocId()
            );

            if (doctorWork == null) {
                logger.error("预约失败：未找到医生 {} 在 {} 的排班信息",
                        patientDoctor.getDocId(), patientDoctor.getDay());
                return false;
            }

            // 检查对应时段是否有号源
            boolean hasAvailableSlots = false;
            if ("上午".equals(patientDoctor.getTimePeriod())) {
                hasAvailableSlots = (doctorWork.getAmwork() != null &&
                        !doctorWork.getAmwork().isEmpty() &&
                        !"0".equals(doctorWork.getAmwork())) &&
                        doctorWork.getCountLeft() != null &&
                        doctorWork.getCountLeft() > 0;
            } else if ("下午".equals(patientDoctor.getTimePeriod())) {
                hasAvailableSlots = (doctorWork.getPmwork() != null &&
                        !doctorWork.getPmwork().isEmpty() &&
                        !"0".equals(doctorWork.getPmwork())) &&
                        doctorWork.getCountLeft() != null &&
                        doctorWork.getCountLeft() > 0;
            }

            if (!hasAvailableSlots) {
                logger.error("预约失败：医生 {} 在 {} {} 已无号源",
                        patientDoctor.getDocId(),
                        patientDoctor.getDay(),
                        patientDoctor.getTimePeriod());
                return false;
            }

            // 3. 创建预约记录
            int result = patientDoctorDao.addPatientDoctor(patientDoctor);

            // 4. 更新医生可预约数量
            if (result > 0) {
                DoctorWork updateWork = new DoctorWork();
                updateWork.setDocId(patientDoctor.getDocId());
                updateWork.setDay(patientDoctor.getDay());
                updateWork.setCountLeft(-1); // 减少一个可预约号源

                int updatedRows = doctorWorkDao.updateCountLeft(updateWork);
                if (updatedRows > 0) {
                    logger.info("预约成功：患者 {} 预约医生 {} 于 {} {}，剩余号源：{}",
                            patientDoctor.getPatientId(),
                            patientDoctor.getDocId(),
                            patientDoctor.getDay(),
                            patientDoctor.getTimePeriod(),
                            doctorWork.getCountLeft() - 1);
                    return true;
                } else {
                    logger.error("更新医生号源失败，回滚预约操作");
                    throw new RuntimeException("更新医生号源失败");
                }
            }
        } catch (Exception e) {
            logger.error("预约挂号失败", e);
            throw new RuntimeException("预约挂号失败", e);
        }
        return false;
    }

    @Override
    @Transactional
    public boolean cancelAppointment(Integer id) {
        try {
            // 1. 查询预约详情
            PatientDoctor appointment = patientDoctorDao.getAppointmentById(id);
            if (appointment == null) {
                logger.error("取消预约失败：ID={} 的预约不存在", id);
                return false;
            }

            // 2. 检查预约状态
            if (appointment.getInfo() != null && appointment.getInfo().contains("[已取消]")) {
                logger.error("取消预约失败：ID={} 的预约已被取消", id);
                return false;
            }

            // 3. 更新预约状态为"已取消"
            int updatedRows = patientDoctorDao.cancelAppointment(id);

            // 4. 如果更新成功，恢复医生可挂号数量
            if (updatedRows > 0) {
                DoctorWork doctorWork = new DoctorWork();
                doctorWork.setDay(appointment.getDay());
                doctorWork.setDocId(appointment.getDocId());
                doctorWork.setCountLeft(1); // 增加一个可挂号数量

                boolean isCountUpdated = doctorWorkDao.updateCountLeft(doctorWork) > 0;
                if (isCountUpdated) {
                    logger.info("成功取消预约并恢复号源：ID={}, 医生={}, 日期={}",
                            id, appointment.getDocId(), appointment.getDay());
                    return true;
                } else {
                    logger.error("恢复号源失败：ID={}, 医生={}, 日期={}",
                            id, appointment.getDocId(), appointment.getDay());
                    throw new RuntimeException("恢复号源失败");
                }
            }

            return false;
        } catch (Exception e) {
            logger.error("取消预约失败", e);
            throw new RuntimeException("取消预约失败", e);
        }
    }

    @Override
    public List<PatientDoctor> getAppointmentsByPatientId(String patientId) {
        logger.info("查询患者 {} 的预约记录", patientId);
        return patientDoctorDao.getPatientDoctorByPatientId(patientId);
    }

    @Override
    public PatientDoctor getAppointmentById(Integer id) {
        logger.info("查询预约ID {} 的详情", id);
        return patientDoctorDao.getAppointmentById(id);
    }

    @Override
    @Transactional
    public boolean updateAppointment(PatientDoctor patientDoctor) {
        try {
            // 1. 检查预约是否存在
            PatientDoctor existingAppointment = patientDoctorDao.getAppointmentById(patientDoctor.getId());
            if (existingAppointment == null) {
                logger.error("更新预约失败：ID={} 的预约不存在", patientDoctor.getId());
                return false;
            }

            // 2. 如果修改了医生或日期，需要检查新的号源
            if (!existingAppointment.getDocId().equals(patientDoctor.getDocId()) ||
                    !existingAppointment.getDay().equals(patientDoctor.getDay())) {

                // 2.1 检查新医生是否有可预约号源
                DoctorWork doctorWork = new DoctorWork();
                doctorWork.setDocId(patientDoctor.getDocId());
                doctorWork.setDay(patientDoctor.getDay());

                List<DoctorWork> workList = doctorWorkDao.getDoctorWorkList(doctorWork);
                if (workList.isEmpty() || (workList.get(0).getCountLeft() != null && workList.get(0).getCountLeft() <= 0)) {
                    logger.error("更新预约失败：医生 {} 在 {} 已无号源",
                            patientDoctor.getDocId(), patientDoctor.getDay());
                    return false;
                }

                // 2.2 恢复原医生的号源
                DoctorWork originalWork = new DoctorWork();
                originalWork.setDocId(existingAppointment.getDocId());
                originalWork.setDay(existingAppointment.getDay());
                originalWork.setCountLeft(1); // 恢复原医生的号源
                doctorWorkDao.updateCountLeft(originalWork);

                // 2.3 占用新医生的号源
                DoctorWork newWork = new DoctorWork();
                newWork.setDocId(patientDoctor.getDocId());
                newWork.setDay(patientDoctor.getDay());
                newWork.setCountLeft(-1); // 占用新医生的号源
                doctorWorkDao.updateCountLeft(newWork);
            }

            // 3. 更新预约信息
            boolean isUpdated = patientDoctorDao.updateAppointment(patientDoctor) > 0;
            if (isUpdated) {
                logger.info("成功更新预约：ID={}", patientDoctor.getId());
                return true;
            } else {
                logger.error("更新预约失败：ID={}", patientDoctor.getId());
                return false;
            }
        } catch (Exception e) {
            logger.error("更新预约失败", e);
            throw new RuntimeException("更新预约失败", e);
        }
    }

    @Override
    public List<PatientDoctor> getAllAppointments() {
        logger.info("查询所有预约记录");
        return patientDoctorDao.getAllAppointments();
    }

    // 分页查询挂号记录
    public Page<RegistrationDTO> getRegistrations(RegistrationQuery query, Pageable pageable) {
        List<RegistrationDTO> list = patientDoctorDao.findRegistrations(
                query.getStartDate(),
                query.getEndDate(),
                query.getPatientName(),
                query.getDoctorName(),
                query.getDepartmentId(),
                query.getStatus()
        );

        // 手动分页
        int total = list.size();
        int start = (int) pageable.getOffset();
        int end = Math.min((start + pageable.getPageSize()), total);

        return new PageImpl<>(list.subList(start, end), pageable, total);
    }

    // 获取科室树
    public List<Department> getDepartmentTree() {
        return departmentDao.findRootDepartments();
    }

    // 获取挂号详情
    public RegistrationDetailDTO getRegistrationDetail(Integer id) {
        // 1. 获取挂号基本信息
        PatientDoctor appointment = patientDoctorDao.findById(id);
        if (appointment == null) {
            throw new ResourceNotFoundException("挂号记录不存在");
        }

        // 2. 获取关联消息
        List<Messageboard> messages = messageboardDao.findByAppointmentId(id);

        // 3. 获取病历信息
        MedicalRecord medicalRecord = medicalRecordDao.findByAppointmentId(id);

        // 4. 构建DTO
        RegistrationDetailDTO detail = new RegistrationDetailDTO();
        BeanUtils.copyProperties(appointment, detail);

        // 5. 设置关联数据
        detail.setMessages(messages);
        if (medicalRecord != null) {
            detail.setDiagnosis(medicalRecord.getDiagnosis());
            detail.setTreatment(medicalRecord.getTreatment());
            detail.setPrescription(medicalRecord.getPrescription());
        }

        return detail;
    }

    // 取消挂号
    @Transactional
    public void cancelRegistration(Integer id) {
        PatientDoctor appointment = patientDoctorDao.findById(id);
        if (appointment == null) {
            throw new ResourceNotFoundException("挂号记录不存在");
        }

        if (!"0".equals(appointment.getStatus())) {
            throw new BusinessException("只有待就诊状态的挂号可以取消");
        }

        int result = patientDoctorDao.updateStatus(id, "2"); // 2: 已取消
        if (result == 0) {
            throw new BusinessException("取消挂号失败");
        }
    }

    // 统计科室挂号量
    public List<DepartmentStatsDTO> getDepartmentStats() {
        return patientDoctorDao.countByDepartment();
    }
}